import argparse
import time
from typing import Any, Optional, Awaitable
from uuid import UUID

from redis import Redis
import pickle
import websocket
from tornado import web, ioloop, httputil
import threading
import json
import logging

from wrenchbox.logging import setup_log

from ourblockchain.blockchain import superID


class IndexHandler(web.RequestHandler):
    def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]:
        pass

    def get(self, h1):
        logging.info("request.arguments: %s", self.request.arguments)
        logging.info("h1: %s", h1)

        error = {
            "status": 400,
            "message": "Wrong Request!",
            "data": None
        }
        # 画家卖画，需要参数：画家id、图片url、定价
        if h1 == 'sell':
            userId = self.request.arguments.get('id')
            url = self.request.arguments.get("url")
            price = self.request.arguments.get("price")
            userId = str(userId[0], encoding='utf-8')
            url = str(url[0], encoding='utf-8')
            price = str(price[0], encoding='utf-8')
            if userId and url and price:
                ws.send(json.dumps({
                    'op': 'merge',
                    'args': {
                        'pool': [{
                            'id': None,
                            'sender': userId,
                            'receiver': superID,
                            'amount': price,
                            'content': {
                                'url': url,
                                'purchase_type': 'setPrice'
                            }
                        }]
                    }
                })
                )
            else:
                self.write(error)
            time.sleep(1)  # 给服务端一点时间存到数据库
            pool = pickle.loads(db.get('pool'))
            for i in pool.copy():
                if i.sender == userId and \
                        i.content.url == url and \
                        i.amount == price:
                    self.write(json.dumps({
                        'status': 200,
                        'message': 'picture loaded'
                    }))
                    break
            else:
                self.write(json.dumps({
                    'status': 400,
                    'message': 'picture register failed'
                }))
        #  用户查画的信息
        elif h1 == 'search':
            url = self.request.arguments.get('url')
            url = str(url[0], encoding='utf-8')
            if url:
                ledger = pickle.loads(db.get('ledger'))
                item = ledger.getUrlOwnerItem(url)
                if item is None:
                    item = ledger.getUrlFirstItem(url)
                    if item is None:
                        self.write(json.dumps({
                            'status': 400,
                            'message': 'no such picture in ledger'
                        }))
                    else:
                        self.write(json.dumps({
                            'status': 200,
                            'message': 'owner is the seller',
                            'data': item
                        }))
                else:
                    self.write(json.dumps({
                        'status': 200,
                        'message': 'found current owner',
                        'data': item
                    }))
            else:
                self.write(error)

        elif h1 == 'balance':
            userId = self.request.arguments.get('id')
            userId = str(userId[0], encoding='utf-8')
            if userId and UUID(userId, version=4):
                ledger = pickle.loads(db.get('ledger'))
                balance = ledger.balance(userId)
                self.write(json.dumps({
                    'status': 200,
                    'message': 'balance gotten',
                    'data': {
                        'balance': balance
                    }
                }))
            else:
                self.write(error)

        elif h1 == 'transship_right':
            userId = self.request.arguments.get('id')
            url = self.request.arguments.get('url')
            userId = str(userId, encoding='utf-8')
            url = str(url, encoding='utf-8')
            if userId and url and UUID(userId, version=4):
                ledger = pickle.loads(db.get('ledger'))
                transship_right = ledger.ableToTransship(url=url, userId=userId)
                self.write(json.dumps({
                    'status': 200,
                    'message': 'transship_right gotten',
                    'data': {
                        'transship_right': transship_right  # 布尔值
                    }
                }))
            else:
                self.write(error)

        elif h1 == 'buy':
            userId = self.request.arguments.get('id')
            url = self.request.arguments.get('url')
            purchase_type = self.request.arguments.get('purchase_type')
            userId = str(userId, encoding='utf-8')
            url = str(url, encoding='utf-8')
            purchase_type = str(purchase_type, encoding='utf-8')
            if userId and url and purchase_type and \
                    UUID(userId, version=4) and purchase_type in ['own', 'transship']:
                ledger = pickle.loads(db.get('ledger'))
                item = ledger.getUrlOwnerItem(url)
                balance = ledger.balance(userId)
                if item is None:
                    item = ledger.getUrlFirstItem(url)
                    if item is None:
                        self.write(json.dumps({
                            'status': 400,
                            'message': 'no such picture in ledger'
                        }))
                    else:  # 图片还在拍卖行托管
                        if purchase_type == 'own':  # 购买类型
                            if balance >= int(item.amount * 1.05):  # 余额ok
                                ws.send(json.dumps({
                                    'op': 'merge',
                                    'args': {
                                        'pool': [{
                                            'id': None,
                                            'sender': userId,
                                            'receiver': superID,
                                            'amount': int(item.amount * 1.05),
                                            'content': {
                                                'url': url,
                                                'purchase_type': 'own'
                                            }
                                        }]
                                    }
                                }))
                                self.write(json.dumps({
                                    'status': 200,
                                    'message': 'success to try to own the picture'
                                }))
                            else:
                                self.write(json.dumps({
                                    'status': 400,
                                    'message': 'No enough money to own the picture'
                                }))
                        else:  # 购买转载权
                            if ledger.ableToTransship(url=url, userId=userId):
                                self.write(json.dumps({
                                    'status': 200,
                                    'message': 'already can transship, no need to buy'
                                }))
                            else:
                                if balance >= int(item.amount * 0.05):  # 余额Ok
                                    ws.send(json.dumps({
                                        'op': 'merge',
                                        'args': {
                                            'pool': [{
                                                'id': None,
                                                'sender': userId,
                                                'receiver': item.sender,
                                                'amount': int(item.amount * 0.05),
                                                'content': {
                                                    'url': url,
                                                    'purchase_type': 'transship'
                                                }
                                            }]
                                        }
                                    }))
                                    self.write(json.dumps({
                                        'status': 200,
                                        'message': 'success to transship the picture'
                                    }))
                                else:
                                    self.write(json.dumps({
                                        'status': 400,
                                        'message': 'No enough money to transship the picture'
                                    }))

                else:  # 图片在人手上
                    if purchase_type == 'own':  # 购买类型
                        if balance >= int(item.amount * 1.05):  # 余额ok
                            ws.send(json.dumps({
                                'op': 'merge',
                                'args': {
                                    'pool': [{
                                        'id': None,
                                        'sender': userId,
                                        'receiver': item.sender,
                                        'amount': int(item.amount * 1.05),
                                        'content': {
                                            'url': url,
                                            'purchase_type': 'own'
                                        }
                                    }]
                                }
                            }))
                            self.write(json.dumps({
                                'status': 200,
                                'message': 'success to try to own the picture'
                            }))
                        else:
                            self.write(json.dumps({
                                'status': 400,
                                'message': 'No enough money to own the picture'
                            }))
                    else:  # 购买转载权
                        if ledger.ableToTransship(url=url, userId=userId):
                            self.write(json.dumps({
                                'status': 200,
                                'message': 'already can transship, no need to buy'
                            }))
                        else:
                            if balance >= int(item.amount * 0.05):  # 余额Ok
                                ws.send(json.dumps({
                                    'op': 'merge',
                                    'args': {
                                        'pool': [{
                                            'id': None,
                                            'sender': userId,
                                            'receiver': item.sender,
                                            'amount': int(item.amount * 0.05),
                                            'content': {
                                                'url': url,
                                                'purchase_type': 'transship'
                                            }
                                        }]
                                    }
                                }))
                                self.write(json.dumps({
                                    'status': 200,
                                    'message': 'success to transship the picture'
                                }))
                            else:
                                self.write(json.dumps({
                                    'status': 400,
                                    'message': 'No enough money to transship the picture'
                                }))
            else:
                self.write(error)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--debug',
        action='store_true',
        default=False,
        help='show debug information'
    )
    parser.add_argument(
        '-p', '--port',
        type=int,
        default=80,
        help='listening port, default:{}'.format(80)
    )
    parser.add_argument(
        '-r', '--redis',
        type=str,
        default='localhost',
        help='redis database file, default: redis.db'
    )
    parser.add_argument(
        '-rp', '--redis_port',
        type=int,
        default=6379,
        help="redis database's port, default:6379"
    )
    parser.add_argument(
        '--dbNum',
        type=int,
        default=0,
        help="num of redis database, default:0"
    )
    args, _ = parser.parse_known_args()
    print(args)

    setup_log(level=logging.DEBUG if args.debug else logging.INFO)
    db = Redis(host=args.redis, port=args.redis_port, db=args.dbNum)

    ws = websocket.WebSocketApp(
        url='ws://localhost:9000/ws',
    )
    clientThread = threading.Thread(target=ws.run_forever)
    clientThread.daemon = True
    clientThread.start()

    if b'pool' not in db.keys():
        db.set('pool', pickle.dumps(set([])))
    if b'ledger' not in db.keys():
        db.set('pool', pickle.dumps(set([])))

    web.Application([
        (r'/web/(\w+)', IndexHandler)
    ]).listen(args.port)
    ioloop.IOLoop.instance().start()
